feat(verifier): infra-free verdict-quality measurement substrate#45
Conversation
검증 알고리즘 고도화: live Ollama 없이 verdict 품질을 측정/회귀방지하는 결정론적 substrate. - core/evaluation/verifier_harness.py: Heuristic/Recorded 전략 + run_corpus_delta (metrics.py 재사용) - core/evaluation/verifier_corpus.py: 단일 SoT CORPUS_CASES(22건, 6 path-role) + 생성기 - eval/verifier-corpus/harness/: candidates.jsonl/expected.json/recorded-ideal.json (생성물, freshness 테스트로 stale 차단) - prompt.py: path-role 앵커 추출(DEFAULT_PATH_ROLE_ANCHORS) + 설정 가능 path_role_decision - verifier.py/client.py/verify_artifact.py: yaml verification.path_role_anchors 배선(default byte-identical, I3 보존) - tests: 정확도 게이트(FR3)/path-role 파라메트라이즈(FR4)/min_confidence sweep(FR6) heuristic baseline: before precision 0.3636 -> after 0.5714, FP_reduction 8, recall 1.0 보존. min_confidence 0.60 유지(플래토 <=0.80). 전체 uv run pytest 746 green. I1~I6 불변식 보존. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request introduces an infra-free verifier accuracy harness and a synthetic finding-level corpus to evaluate verifier quality without requiring a live model or network. It adds deterministic and recorded verifier strategies, configurable path-role anchors via YAML, and comprehensive tests for validation and threshold sweeps. The review feedback suggests optimizing redundant function calls in verifier_corpus.py, adding defensive type validation for loaded JSON in RecordedVerifierStrategy.from_file to prevent potential runtime errors, and incorporating type hints for the strategy parameter using typing.TYPE_CHECKING to enhance code maintainability.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| candidates = candidates or build_corpus_candidates() | ||
| by_id = {finding.finding_id: finding for finding in candidates} | ||
| responses: dict[str, dict] = {} | ||
| for case, finding in zip(CORPUS_CASES, build_corpus_candidates()): |
There was a problem hiding this comment.
이 함수에서 build_corpus_candidates()가 여러 번 호출되고 있습니다. candidates가 제공되지 않았을 때 기본값으로 사용하기 위해 한 번 호출하고, 루프를 돌 때 zip에서 또 한 번 호출합니다. build_corpus_candidates()의 결과를 변수에 저장하여 재사용하면 불필요한 객체 생성과 중복 호출을 방지할 수 있습니다.
| candidates = candidates or build_corpus_candidates() | |
| by_id = {finding.finding_id: finding for finding in candidates} | |
| responses: dict[str, dict] = {} | |
| for case, finding in zip(CORPUS_CASES, build_corpus_candidates()): | |
| default_candidates = build_corpus_candidates() | |
| candidates = candidates or default_candidates | |
| by_id = {finding.finding_id: finding for finding in candidates} | |
| responses: dict[str, dict] = {} | |
| for case, finding in zip(CORPUS_CASES, default_candidates): |
There was a problem hiding this comment.
반영했습니다 (e2f2c11) — build_corpus_candidates()를 1회만 호출하고 zip(CORPUS_CASES, candidates)로 정렬해 중복 호출을 제거했습니다. 출력은 byte-identical이라 freshness 테스트 green 유지.
| responses = data.get("responses", data) if isinstance(data, Mapping) else data | ||
| return cls(responses=responses, min_confidence=min_confidence) | ||
|
|
There was a problem hiding this comment.
RecordedVerifierStrategy.from_file에서 로드된 JSON 데이터가 Mapping 타입인지 검증하는 로직이 미흡합니다. 만약 JSON 파일이 객체(dict)가 아닌 리스트나 다른 타입일 경우, isinstance(data, Mapping)가 False가 되어 responses에 그대로 할당되고, 이후 verify 메서드에서 self.responses.get 호출 시 AttributeError가 발생할 수 있습니다. 방어적 프로그래밍 관점에서 로드된 데이터와 responses가 Mapping 타입인지 명확히 검증하고 예외를 던지도록 개선하는 것이 좋습니다. 또한, 이러한 방어적 타입 검증을 구현할 때는 None, 숫자, 불리언, 리스트, 딕셔너리 등 다양한 예기치 않은 타입을 포함하는 포괄적인 단위 테스트를 추가하여 견고성을 보장해야 합니다.
data = json.loads(Path(path).read_text(encoding="utf-8"))
if not isinstance(data, Mapping):
raise ValueError("Recorded responses file must contain a JSON object.")
responses = data.get("responses", data)
if not isinstance(responses, Mapping):
raise ValueError("Recorded responses must be a mapping.")
return cls(responses=responses, min_confidence=min_confidence)References
- When implementing defensive type validation for parsed JSON fields (e.g., verifying a field is a string), ensure robustness by adding comprehensive unit tests that cover various unexpected types, including None, numbers, booleans, lists, and dictionaries.
There was a problem hiding this comment.
반영했습니다 (e2f2c11) — 로드된 JSON과 responses가 Mapping이 아니면 ValueError로 fail-closed 처리하고, 비-객체 타입(list/scalar/bool/null/non-mapping responses) 파라메트라이즈 테스트를 추가했습니다.
| return cls(responses=responses, min_confidence=min_confidence) | ||
|
|
||
|
|
||
| def verify_candidates(candidates: list[Finding], strategy) -> list[Finding]: |
There was a problem hiding this comment.
반영했습니다 (e2f2c11) — VerifierStrategy Protocol을 추가해 verify_candidates/run_corpus_delta의 strategy에 타입 힌트를 부여했습니다.
- RecordedVerifierStrategy.from_file: fail-closed ValueError on non-mapping JSON (avoids later AttributeError) + parametrized type-validation test - VerifierStrategy Protocol typing for verify_candidates/run_corpus_delta - build_ideal_responses: single build_corpus_candidates() call (dedup) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| class VerifierStrategy(Protocol): | ||
| """Structural type for a candidate-to-result verifier strategy.""" | ||
|
|
||
| def verify(self, finding: Finding) -> VerifierResult: ... |
Outcome
verifier-algorithm-enhancement-HANDOFF.md를 grill-to-spec(자문자답) → agentic-execution으로 수행한 결과. live Ollama 인프라 없이 verifier verdict 품질을 측정·개선·회귀방지하는 결정론적 substrate를 세운다. HANDOFF가 "이 세션의 진짜 첫 작업"으로 지목한 측정 하네스 부재(§5 MISSING #1~#7)를 해소한다.무엇을
core/evaluation/verifier_harness.py—HeuristicVerifierStrategy(path-role 앵커, 결정론적) /RecordedVerifierStrategy(기록 응답 재생) +run_corpus_delta. 기존metrics.py를 재사용(새 메트릭 엔진 없음).core/evaluation/verifier_corpus.py— 단일 SoTCORPUS_CASES(22건=8 TP+14 FP, 6 path-role 전부). 생성기가eval/verifier-corpus/harness/{candidates.jsonl,expected.json,recorded-ideal.json}산출, freshness 테스트가 stale 차단.prompt.pyDEFAULT_PATH_ROLE_ANCHORS추출 +path_role_decision(role, anchors); yamlverification.path_role_anchors를verify_artifact.py에서 검증·partial-merge 배선. default 미설정 시 프롬프트 byte-identical(I3 보존).측정 결과 (infra-free)
0.3636→ after0.5714, FP reduction8, recall1.0보존(FN 0).1.0, FP reduction14, strict gate(precision≥0.90/recall≥0.99) PASS.불변식
I1 DEFAULT-OFF · I2 fail-closed · I3 redacted-only · I5 NEEDS_REVIEW no-write · I6 public-safe — 전부 보존. 앵커/corpus/recorded 산출물에 raw secret 없음(candidates.jsonl은
salted-sha256:해시만).검증
uv run pytest746 passed (신규 게이트 포함, ci/pytest가 강제).governance.public_safety(변경 경로) exit 0;render --validate/--check,validate_ledger모두 exit 0.셀프 멀티에이전트 리뷰
12 에이전트 / 5 차원(invariants·correctness·spec-compliance·test-quality·public-safety), 적대적 검증 포함. confirmed 1 nit(sweep monotonicity 단언이 평탄 수열에도 통과) → 이미 수정(
reductions[0] > reductions[-1]). spec-compliance 재확인: FR1~FR8 전부 MET, hidden defer 없음, GO.남은 것 (코드 defer 아님)
실제 Ollama end-to-end 정확도 측정 = Tailscale Ubuntu 박스 복귀 시
eval/verifier-corpus/README.md의 single command 1회 →recorded-ideal.json자리에 실모델 출력 drop-in.🤖 Generated with Claude Code